import SparkMD5 from 'spark-md5'
import {message } from 'ant-design-vue';
import {uploadAction} from '@/api/manage'

// 如果上传错误，获取报错信息
// function getError(action, option, xhr) {
//   let msg
//   if (xhr.response) {
//     msg = `${xhr.response.msg || xhr.response}`
//   } else if (xhr.responseText) {
//     msg = `${xhr.responseText}`
//   } else {
//     msg = `fail to post ${action} ${xhr.status}`
//   }
//   const err = new Error(msg)
//   err.status = xhr.status
//   err.method = 'post'
//   err.url = action
//   return err
// }

// 上传成功完成合并之后，获取服务器返回的信息
// function getBody(xhr) {
//   const text = xhr.msg || xhr.msg
//   if (!text) {
//     return text
//   }
//   try {
//     return JSON.parse(text)
//   } catch (e) {
//     return text
//   }
// }

// 分片上传的自定义请求，以下请求会覆盖element的默认上传行为
export default function upload(option) {
  console.log('fileInfo.option',option)

  if (typeof XMLHttpRequest === 'undefined') {
    return
  }
  const spark = new SparkMD5.ArrayBuffer()// md5的ArrayBuffer加密类
  const fileReader = new FileReader()// 文件读取类
  const action = option.action // 文件上传上传路径
  const chunkSize = 1024 * 1024 * 30 // 单个分片大小
  let chunkContinuesNum = 0
  let chunkOffset = 0 // 当前分片的偏移值
  let md5 = '' // 文件的唯一标识
  const optionFile = option.file // 需要分片的文件
  let fileChunkedList = [] // 文件分片完成之后的数组
  const percentage = [] // 文件上传进度的数组，单项就是一个分片的进度

  // 首次进来并没有选择文件，因此直接return
  if (option.file === undefined) {
    return
  }
  // 文件开始分片，push到fileChunkedList数组中
  for (let i = 0; i < optionFile.size; i = i + chunkSize) {
    const tmp = optionFile.slice(i, Math.min((i + chunkSize), optionFile.size))
    fileChunkedList.push(tmp)
    // 将每一个分片的数据读取出来
    while (fileReader.readyState !== 1) {
      fileReader.readAsArrayBuffer(tmp)
      break
    }
  }
  // 在文件读取完毕之后，开始计算文件md5，作为文件唯一标识
  fileReader.onload = async (e) => {
    spark.append(e.target.result)
    md5 = spark.end()
    console.log('文件md5为--------', md5)

    // 将fileChunkedList转成FormData对象，并加入上传时需要的数据
    fileChunkedList = fileChunkedList.map((item, index) => {
      const formData = new FormData()
      if (option.data) {
        // 额外加入外面传入的data数据
        Object.keys(option.data).forEach(key => {
          formData.append(key, option.data[key])
        })
        // 这些字段看后端需要哪些，就传哪些，也可以自己追加额外参数
        formData.append('chunkFile', item, option.file.name)// 文件
        formData.append('chunkNum', index + 1)// 当前文件块
        formData.append('chunkSize', chunkSize)// 单个分块大小
        // formData.append('currentChunkSize', item.size)// 当前分块大小
        if (index + 1 === chunkContinuesNum) {
          formData.append('offset', chunkOffset)// 当前分块偏移值
        }
        formData.append('fileSize', optionFile.size)// 文件总大小
        formData.append('fileMd5', md5)// 文件标识
        formData.append('totalChunks', fileChunkedList.length)// 总块数
      }
      return {formData: formData, index: index}
    })
    console.log('fileChunkedList',fileChunkedList)

    // 更新上传进度条百分比的方法
    const updataPercentage = (e) => {
      let loaded = 0// 当前已经上传文件的总大小
      percentage.forEach(item => {
        loaded += item
      })
      e.percent = loaded / optionFile.size * 100
      option.onProgress(e)
    }

    // 创建队列上传任务，limit是上传并发数
    function sendRequest(chunks, limit = 1) {
      return new Promise((resolve, reject) => {
        message.success('开始上传分片')
        const len = chunks.length
        let counter = 0
        let isStop = false
        const start = async () => {
          if (isStop) {
            return
          }
          const item = chunks.shift()
          console.log('item',item);
          if (item) {
            // 断点续传，跳过已上传的分片
            if (counter + 1 >= chunkContinuesNum) {
              // 给后端发送文件合并请求
              const chunkUpload = await uploadAction(action,item.formData)
              if (chunkUpload.code !== 200) {
                message.error(chunkUpload.message)
                isStop = true
                reject(chunkUpload)
              }
            }
            if (counter === len - 1) {
              // 最后一个上传完成
              resolve()
            } else {
              counter++
              // 更新进度条
              percentage[counter] = chunkSize
              updataPercentage(e)
              start()
            }
          }
        }
        while (limit > 0) {
          setTimeout(() => {
            start()
          }, Math.random() * 1000)
          limit -= 1
        }
      })
    }

    try {
      message.success("开始计算分片")
      // 先注册/获取上传文件信息
      const registerData=new FormData()
      registerData.append('fileName',option.file.name)
      registerData.append('fileMd5',md5)
      registerData.append('fileSize',optionFile.size)
      registerData.append('chunkSize',chunkSize)
      registerData.append('totalChunks',fileChunkedList.length)
      // const registerData = {
      //   fileName: option.file.name, // 文件名-合并块时使用
      //   fileMd5: md5, // 文件MD5值，防止篡改
      //   fileSize: optionFile.size, // 文件总大小
      //   chunkSize: chunkSize, // 每个块的大小
      //   totalChunks: fileChunkedList.length // 块的总数量
      // }
      // 给后端发送文件合并请求
      const registerResInfo = await uploadAction('/sys/fileUpload/chunk/register',registerData)
      if (registerResInfo.code !== 200) {
        message.error(registerResInfo.message)
        return
      } else {
        let resJson = JSON.parse(registerResInfo.result)
        if (resJson.finish) {
          message.success('已经上传，不需重复上传！')
          option.onError()
          return
        }
      }
      // 断点续传设置续传块编号和偏移值
      let registerResData = JSON.parse(registerResInfo.result)
      chunkContinuesNum = registerResData.chunkNum
      chunkOffset = registerResData.chunkOffset

      // 调用上传队列方法 等待所有文件上传完成
      await sendRequest(fileChunkedList, 1)
      // 这里的参数根据自己实际情况写
      const mergeData=new FormData()
      mergeData.append('fileMd5',md5)
      mergeData.append('chunkSize',chunkSize)
      mergeData.append('totalChunks',fileChunkedList.length)
      // const data = {
      //   fileMd5: md5, // 文件MD5值，防止篡改
      //   chunkSize: chunkSize, // 每个块的大小
      //   totalChunks: registerData.totalChunks // 块的总数量
      // }
      message.success("开始合并分片")
      // 给后端发送文件合并请求
      const fileInfo = await uploadAction('/sys/fileUpload/chunk/merge',mergeData)
      if (fileInfo.code === 200) {
        // const success = getBody(fileInfo)
        message.success('文件上传成功！')
        option.onSuccess()
        return
      }
    } catch (error) {
      console.log('error',error)
      option.onError()
    }
  }
}